HID: Avoid ABI change in 4.17.6
authorBen Hutchings <ben@decadent.org.uk>
Wed, 11 Jul 2018 23:39:38 +0000 (00:39 +0100)
committerSalvatore Bonaccorso <carnil@debian.org>
Fri, 20 Jul 2018 21:08:27 +0000 (22:08 +0100)
Commit 8f732850df1b "HID: core: allow concurrent registration of
drivers" introduced atomic bit-operations on hid_device::status, and
changed its type from unsigned int to unsigned long as required for
those operations.

Revert the type change and use cmpxchg() for the bit-operations,
since it supports unsigned int.

Gbp-Pq: Topic debian
Gbp-Pq: Name hid-avoid-abi-change-in-4.17.6.patch

drivers/hid/hid-core.c
include/linux/hid.h

index c1ce4baeeacad146242d9c9d20a64a3eb5a1d588..43af36355e106b4af9036a60a2575b0c3c9b2923 100644 (file)
@@ -1929,6 +1929,34 @@ static int hid_bus_match(struct device *dev, struct device_driver *drv)
        return hid_match_device(hdev, hdrv) != NULL;
 }
 
+static void clear_status_flag(unsigned int flag, unsigned int *status)
+{
+       unsigned int expect, old;
+
+       expect = READ_ONCE(*status);
+       for (;;) {
+               old = cmpxchg(status, expect, expect & ~flag);
+               if (old == expect)
+                       break;
+               expect = old;
+       }
+}
+
+static bool test_and_set_status_flag(unsigned int flag, unsigned int *status)
+{
+       unsigned int expect, old;
+
+       expect = READ_ONCE(*status);
+       for (;;) {
+               old = cmpxchg(status, expect, expect | flag);
+               if (old == expect)
+                       break;
+               expect = old;
+       }
+
+       return old & flag;
+}
+
 static int hid_device_probe(struct device *dev)
 {
        struct hid_driver *hdrv = to_hid_driver(dev->driver);
@@ -1942,7 +1970,7 @@ static int hid_device_probe(struct device *dev)
        }
        hdev->io_started = false;
 
-       clear_bit(ffs(HID_STAT_REPROBED), &hdev->status);
+       clear_status_flag(HID_STAT_REPROBED, &hdev->status);
 
        if (!hdev->driver) {
                id = hid_match_device(hdev, hdrv);
@@ -2208,7 +2236,7 @@ static int __hid_bus_reprobe_drivers(struct device *dev, void *data)
 
        if (hdev->driver == hdrv &&
            !hdrv->match(hdev, hid_ignore_special_drivers) &&
-           !test_and_set_bit(ffs(HID_STAT_REPROBED), &hdev->status))
+           !test_and_set_status_flag(HID_STAT_REPROBED, &hdev->status))
                return device_reprobe(dev);
 
        return 0;
index 2a4c0900e46afe2cfac46d1a17f0922b6f9eaa6a..4eca5e3ecec65eefe4ec7d0afdc016299c39aded 100644 (file)
@@ -569,7 +569,7 @@ struct hid_device {                                                 /* device report descriptor */
        bool battery_avoid_query;
 #endif
 
-       unsigned long status;                                           /* see STAT flags above */
+       unsigned int status;                                            /* see STAT flags above */
        unsigned claimed;                                               /* Claimed by hidinput, hiddev? */
        unsigned quirks;                                                /* Various quirks the device can pull on us */
        bool io_started;                                                /* If IO has started */